const { reject } = require('lodash')

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class Mypromise {
  constructor(experce) {
    // 捕获函数执行的错误
    try {
      experce(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }
  // promise 的状态
  status = PENDING
  // resolev 返回值
  value = undefined
  // reject 返回值
  reason = undefined
  // 缓存 fulfillCallback
  fulfillCallback = []
  // 缓存 rejectCallback
  rejectCallback = []

  resolve = value => {
    // 判断是否处于pending 状态，不是的话停止继续执行
    if (this.status !== PENDING) return
    // 改变为 pending 状态为 fulfilled 状态
    this.status = FULFILLED
    // 保存 resolve 传递的参数值
    this.value = value
    // 判断 fulfillCallback 是否有函数
    if (this.fulfillCallback.length) {
      // 异步调用执行
      this.fulfillCallback.forEach(fn => fn())
    }
  }

  reject = reason => {
    // 判断是否处于pending 状态，不是的话停止继续执行
    if (this.status !== PENDING) return
    // 改变为 pending 状态为 rejected 状态
    this.status = REJECTED
    // 保存 reject 传递的参数值
    this.reason = reason
    // 判断 rejectCallback 是否有函数
    if (this.rejectCallback.length) {
      // 异步调用执行
      this.rejectCallback.forEach(fn => fn())
    }
  }

  then(fulfillCallback, rejectCallback) {
    fulfillCallback = fulfillCallback ? fulfillCallback : value => value
    rejectCallback = rejectCallback
      ? rejectCallback
      : reason => {
          throw reason
        }
    const promise2 = new Mypromise((resolve, reject) => {
      // 判断 status 状态
      if (this.status === FULFILLED) {
        // 为了拿到 promise2 这个变量
        setTimeout(() => {
          // 捕获函数执行时的错误
          try {
            const x = fulfillCallback(this.value)
            // 判断 x 的值为普通值还是promise值，和是否引起循环调用，即 x===promise2
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const x = rejectCallback(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else {
        // 异步函数调用，保存 fulfillCallback 回调
        this.fulfillCallback.push(() => {
          // 为了拿到 promise2 这个变量
          setTimeout(() => {
            try {
              const x = fulfillCallback(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
        // 异步函数调用，保存 rejectCallback 回调
        this.rejectCallback.push(() => {
          // 为了拿到 promise2 这个变量
          setTimeout(() => {
            try {
              const x = rejectCallback(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
      }
    })
    return promise2
  }

  catch(rejectCallback) {
    //  即调用 then 方法的 reject 回调
    return this.then(undefined, rejectCallback)
  }

  finally(finallyCallback) {
    // 不管成功状态还是失败状态都执行一次
    // 要链式调用，所以要返回promise对象，把 promise 的值传递给下一个 then
    // 如果 finallyCallback 回调有返回值，且是异步执行的话，借助 resolve 方法返回相应的 promise 的值
    //
    return this.then(
      value => {
        return Mypromise.resolve(finallyCallback()).then(() => value)
      },
      reason => {
        return Mypromise.resolve(finallyCallback()).then(() => {
          throw reason
        })
      }
    )
  }

  static all(array) {
    // 按参数顺序返回值，只有全部正确返回才是 resolve，有一个错就返回 reject
    // 返回值个数===array.length，
    let arr = []
    let index = 0
    return new Promise((resolve, reject) => {
      function addData(i, val) {
        arr[i] = val
        index++
        if (index === array.length) {
          resolve(arr)
        }
      }
      for (let i = 0; i < array.length; i++) {
        const element = array[i]
        if (element instanceof Mypromise) {
          try {
            element.then(
              res => addData(i, res),
              rej => reject(rej)
            )
          } catch (e) {
            console.log('catch')
            reject(e)
          }
        } else {
          addData(i, element)
        }
      }
    })
  }

  static resolve(value) {
    // if (value instanceof Mypromise) {
    //   return value
    // } else {
    //   return new Mypromise((resolve, rejcet) => {
    //     resolve(value)
    //   })
    // }
    // 判断参数是普通值还是promise值
    // promise 值直接返回
    // 普通值，返回 resolve 状态的promise函数
    if (value instanceof Mypromise) {
      return value
    }
    return new Mypromise((resolve, reject) => {
      resolve(value)
    })
  }

  static reject(reason) {
    // 判断参数是普通值还是promise值
    // promise 值直接返回
    // 普通值，返回 reject 状态的promise函数
    if (reason instanceof Mypromise) return reason
    return new Mypromise((resolve, reject) => {
      reject(reason)
    })
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError('不能循环调用'))
  }
  if (x instanceof Mypromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

const p1 = function () {
  return new Mypromise((resolve, reject) => {
    setTimeout(() => {
      // throw new Error('throw 错误')
      resolve('p1 start')
      // reject('p1 错误')
    }, 1200)
  })
}

console.log('resolve 演示')
new Mypromise((resolve, reject) => {
  setTimeout(() => {
    // throw new Error('throw')
    reject('陈公公 失败')
    resolve('陈公公')
  }, 2000)
})
  .finally(() => {
    console.log('finally')
    return p1()
  })
  .then(res => {
    console.log(res)
  })
  .catch(res => {
    console.log('catch', res)
  })

// Mypromise.reject(p1)
//   .then(res => {
//     console.log(res)
//   })
//   .catch(rej => {
//     console.log('catch', rej)
//   })

// Mypromise.all([p1(), 'aaa', 'bbb']).then(
//   res => {
//     console.log('all', res)
//   },
//   rej => {
//     console.log('all rej', rej)
//   }
// )
